#include "ffhttpd.h"

// 初始化线程池tp,它接受一个指向 THEADPOOL 结构体的指针作为参数
void threadpool_init(THEADPOOL *tp)
{
	int i;										   // 定义一个整型变量 i
	memset(tp, 0, sizeof(THEADPOOL));			   // 使用 memset 函数将 tp 所指向的结构体初始化为全 0,即清空该结构体
	pthread_mutex_init(&tp->mutex, NULL);		   // 使用 pthread_mutex_init 函数初始化 tp 所指向的结构体的互斥锁,NULL 参数表示不使用任何属性
	pthread_cond_init(&tp->cond, NULL);			   // 使用 pthread_cond_init 函数初始化 tp 所指向的结构体的条件变量,NULL 参数表示不使用任何属性
	for (i = 0; i < FFHTTPD_MAX_WORK_THREADS; i++) // 遍历所有工作线程
	{
		// 在当前线程中创建新的工作线程,将 handle_http_request 函数作为新线程的入口点,将 tp 指针作为参数传递给新线程
		pthread_create(&tp->threads[i], NULL, handle_http_request, tp);
	}
}

// 释放线程池tp,它接受一个指向 THEADPOOL 结构体的指针作为参数
void threadpool_free(THEADPOOL *tp)
{
	int i;										   // 定义一个整型变量 i
	pthread_mutex_lock(&tp->mutex);				   // 获取 tp 所指向的结构体的互斥锁,这可以保证并发访问的线程安全性
	tp->size = -1;								   // 将线程池的大小设置为 -1,表示不再接受新的任务
	pthread_cond_broadcast(&tp->cond);			   // 向所有等待在条件变量 tp->cond 上的线程发送广播信号,告知它们可以退出或者开始工作了
	pthread_mutex_unlock(&tp->mutex);			   // 释放互斥锁,允许其他线程可以访问
	for (i = 0; i < FFHTTPD_MAX_WORK_THREADS; i++) // 遍历所有工作线程
	{
		pthread_join(tp->threads[i], NULL); // 等待每个工作线程结束,避免产生僵尸线程.NULL 参数表示不返回线程的返回值
	}
	pthread_mutex_destroy(&tp->mutex); // 销毁互斥锁,释放系统资源
	pthread_cond_destroy(&tp->cond);   // 销毁条件变量,释放系统资源
}

/*
 * 从线程池中取出一个套接字的函数
 */
int threadpool_dequeue(THEADPOOL *tp)
{
	int fd = -1;					// 初始化取出的套接字为 -1
	pthread_mutex_lock(&tp->mutex); // 使用互斥锁保护线程池,防止多线程同时访问
	while (tp->size == 0)			// 如果线程池为空,则等待条件
		pthread_cond_wait(&tp->cond, &tp->mutex);
	if (tp->size != -1)
	{														  // 如果线程池不为空
		fd = tp->conns[tp->head++ % FFHTTPD_MAX_CONNECTIONS]; // 从线程池头部取出一个套接字
		tp->size--;											  // 减少线程池中的连接数
		pthread_cond_signal(&tp->cond);						  // 发送条件信号,通知可能在等待的线程有新的连接可以处理
	}
	pthread_mutex_unlock(&tp->mutex); // 释放互斥锁,允许其他线程访问资源
	return fd;						  // 返回取出的套接字
}

/**
 * 将一个新的套接字(int)添加到线程池中
 * 接收两个参数,第一个是线程池的指针,第二个是要添加的套接字
 */
void threadpool_enqueue(THEADPOOL *tp, int fd)
{
	pthread_mutex_lock(&tp->mutex);				// 使用互斥锁保证线程安全
	while (tp->size == FFHTTPD_MAX_CONNECTIONS) // 当线程池的大小达到最大连接数时,线程等待条件
		pthread_cond_wait(&tp->cond, &tp->mutex);

	// 如果线程池的大小没有达到最大连接数
	if (tp->size != -1)
	{
		tp->conns[tp->tail++ % FFHTTPD_MAX_CONNECTIONS] = fd; // 将套接字添加到线程池的尾部,如果超过了最大连接数,则循环到头部继续添加
		tp->size++;											  // 更新线程池的大小
		pthread_cond_signal(&tp->cond);						  // 发送条件信号,通知可能在等待的线程有新的连接可以处理
	}
	pthread_mutex_unlock(&tp->mutex); // 释放互斥锁,允许其他线程访问资源
}
